home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK2.toast / Development Kits (Disc 2) / QuickTime / Programming Stuff / Documentation / develop articles / develop Issue 23 / Internet Config / IC 1.1 / ICAppSourceKit1.1 / ICMovableModal.p < prev    next >
Encoding:
Text File  |  1997-02-26  |  7.0 KB  |  266 lines  |  [TEXT/PJMM]

  1. unit ICMovableModal;
  2.  
  3. { This unit implements a MovableModalDialog routine similar to }
  4. { the Toolbox routine ModalDialog, to be used for movable modal dialogs }
  5.  
  6. { Based on code by Merzwaren <piovanel@dsi.unimi.it> }
  7.  
  8. interface
  9.  
  10.     procedure DisableMenuBar (var saved_state: univ Ptr; hmnuID: Integer);
  11.     procedure ReEnableMenuBar (var saved_state: univ Ptr);
  12.     procedure MovableModalDialog (filterProc: ProcPtr; var itemHit: Integer);
  13.  
  14. implementation
  15.  
  16.     uses
  17.         GestaltEqu, ICTypes, ICDialogs, ICGlobals;
  18.  
  19.     const
  20.         kSystemMenuThreshold = -16000;        { menu IDs <= than this are used by the system }
  21.         kMovableModalEventMask = mDownMask + mUpMask + keyDownMask + keyUpMask + autoKeyMask + updateMask + activMask + app4Mask;
  22.  
  23.     type
  24.         MenuEntry = record
  25.                 hMenu: MenuHandle;
  26.                 leftEdge: Integer;
  27.             end;
  28.  
  29.         MenuList = record
  30.                 offsetToLastMenu: Integer;
  31.                 rightmostEdge: Integer;
  32.                 unused: Integer;
  33.                 theMenus: array[0..1000] of MenuEntry;
  34.             end;
  35.         MenuListPtr = ^MenuList;
  36.         MenuListHandle = ^MenuListPtr;
  37.  
  38.         MenuBarState = record
  39.                 mbsBarEnable: LongInt;
  40.                 mbsEditEnable: LongInt;
  41.             end;
  42.         MenuBarStatePtr = ^MenuBarState;
  43.  
  44.     function HasHelpManager: Boolean;
  45.         var
  46.             response: LongInt;
  47.     begin
  48.         HasHelpManager := (Gestalt(gestaltHelpMgrAttr, response) = noErr) & BTST(response, gestaltHelpMgrPresent);
  49.     end;
  50.  
  51.     function LMGetMenuList: Handle;
  52.     inline
  53.         $2EB8, $0A1C;            { MOVE.L $0A1C,(SP) }
  54.  
  55.     function HMSetMenuResID (menuID: integer; resID: integer): OSErr;
  56.     inline
  57.         $303C, $020D, $A830;
  58.  
  59.     procedure DisableMenuBar (var saved_state: univ Ptr; hmnuID: Integer);
  60.         var
  61.             menuList: MenuListHandle;
  62.             i, nMenus: Integer;
  63.             theMenu: MenuHandle;
  64.             menuID: Integer;
  65.             menuEnable: LongInt;
  66.             theDialog: DialogPtr;
  67.             hasBalloons, needEditMenu: Boolean;
  68.             junk: OSErr;
  69.             state: MenuBarStatePtr;
  70.     begin
  71.         hasBalloons := HasHelpManager;
  72.  
  73.         theDialog := FrontWindow;
  74.         needEditMenu := (theDialog <> nil) & (SelectedTextItem(theDialog) > 0);
  75.  
  76.         menuList := MenuListHandle(LMGetMenuList);
  77.         nMenus := menuList^^.offsetToLastMenu div SizeOf(MenuEntry);
  78.  
  79.         saved_state := NewPtr(SizeOf(MenuBarState));
  80.         state := MenuBarStatePtr(saved_state);
  81.  
  82.         state^.mbsBarEnable := 0;
  83.         for i := 0 to nMenus - 1 do begin
  84.             theMenu := menuList^^.theMenus[i].hMenu;
  85.             menuID := theMenu^^.menuID;
  86.  
  87.             if (menuID > kSystemMenuThreshold) then begin { do nothing if this is a system menu }
  88.  
  89.                 if (menuID = M_Edit) then begin
  90.                     state^.mbsEditEnable := theMenu^^.enableFlags;
  91.                     if needEditMenu then begin
  92.                         theMenu^^.enableFlags := 1 + BSL(1, EM_Cut) + BSL(1, EM_Copy) + BSL(1, EM_Paste);
  93.                     end
  94.                     else begin
  95.                         DisableItem(theMenu, 0);
  96.                     end;
  97.                 end
  98.                 else begin { if this menu is enabled, disable it and set the corresponding bit  }
  99.                     if (BTST(theMenu^^.enableFlags, 0)) then begin
  100.                         BSET(state^.mbsBarEnable, i);
  101.                         DisableItem(theMenu, 0);
  102.                     end;
  103.  
  104.                     if (hasBalloons) then begin { remap the help strings for this menu }
  105.                         junk := HMSetMenuResID(menuID, hmnuID);
  106.                     end;
  107.                 end;
  108.             end;
  109.         end;
  110.  
  111.         HiliteMenu(0);
  112.         DrawMenuBar;
  113.     end;
  114.  
  115.     procedure ReEnableMenuBar (var saved_state: univ Ptr);
  116.         var
  117.             menuList: MenuListHandle;
  118.             i, nMenus: Integer;
  119.             theMenu: MenuHandle;
  120.             menuID: Integer;
  121.             hasBalloons: Boolean;
  122.             err: OSErr;
  123.             state: MenuBarStatePtr;
  124.     begin
  125.         state := MenuBarStatePtr(saved_state);
  126.  
  127.         hasBalloons := HasHelpManager;
  128.  
  129.         menuList := MenuListHandle(LMGetMenuList);
  130.         nMenus := menuList^^.offsetToLastMenu div SizeOf(MenuEntry);
  131.  
  132.         for i := 0 to nMenus - 1 do begin
  133.             theMenu := menuList^^.theMenus[i].hMenu;
  134.             menuID := theMenu^^.menuID;
  135.  
  136.             if (menuID > kSystemMenuThreshold) then begin
  137.                 if (menuID = M_Edit) then begin
  138.                     theMenu^^.enableFlags := state^.mbsEditEnable;
  139.                 end
  140.                 else if (BTST(state^.mbsBarEnable, i)) then begin
  141.                     EnableItem(theMenu, 0);
  142.                 end;
  143.                 if (hasBalloons) then begin
  144.                     err := HMSetMenuResID(menuID, -1);
  145.                 end;
  146.             end;
  147.         end;
  148.  
  149.         DisposePtr(saved_state);
  150.         saved_state := nil;
  151.         DrawMenuBar;
  152.     end;
  153.  
  154.     function CallFilter (dialog: DialogPtr; var event: EventRecord; var item: Integer; filterProc: ProcPtr): Boolean;
  155.     inline
  156.         $205F, $4E90;
  157.  
  158.     procedure CallBeeper (soundNo: Integer; beeperProc: ProcPtr);
  159.     inline
  160.         $205F, $4E90;
  161.  
  162.     function LMGetDABeeper: ProcPtr;
  163.     inline
  164.         $2EB8, $0A9C;            { MOVE.L $0A9C,(SP) }
  165.  
  166.     function DoMenuChoice (theDialog: DialogPtr; var theEvent: EventRecord; var itemHit: Integer; menuChoice: LongInt): Boolean;
  167.         var
  168.             menuID, menuItem: Integer;
  169.             currentEditField, itemType: Integer;
  170.             junk: OSErr;
  171.     begin
  172.         DoMenuChoice := false;
  173.  
  174.         menuID := HiWord(menuChoice);
  175.         menuItem := LoWord(menuChoice);
  176.  
  177.         if (menuID = M_Edit) then begin
  178.             currentEditField := SelectedTextItem(theDialog);
  179.             GetDItemKind(theDialog, currentEditField, itemType);
  180.  
  181.             if (BAND(itemType, itemDisable) = 0) then begin { if the current edit field is an enabled item, exit from MovableModalDialog loop }
  182.                 DoMenuChoice := true;
  183.                 itemHit := currentEditField;
  184.             end;
  185.  
  186.             if (menuItem = EM_Cut) then begin
  187.                 DlgCut(theDialog);
  188.                 junk := ZeroScrap;
  189.                 junk := TEToScrap;
  190.             end
  191.             else if (menuItem = EM_Copy) then begin
  192.                 DlgCopy(theDialog);
  193.                 junk := ZeroScrap;
  194.                 junk := TEToScrap;
  195.             end
  196.             else if (menuItem = EM_Paste) then begin
  197.                 DlgPaste(theDialog);
  198.             end;
  199.         end;
  200.  
  201.         HiliteMenu(0);
  202.     end;
  203.  
  204.     function HandleMouseDown (theDialog: DialogPtr; var theEvent: EventRecord; var itemHit: Integer): Boolean;
  205.         var
  206.             partCode: Integer;
  207.             wind: WindowPtr;
  208.             beeper: ProcPtr;
  209.             dragRect: Rect;
  210.     begin
  211.         HandleMouseDown := false;
  212.  
  213.         partCode := FindWindow(theEvent.where, wind);
  214.  
  215.         if (partCode = inMenuBar) then begin
  216.             HandleMouseDown := DoMenuChoice(theDialog, theEvent, itemHit, MenuSelect(theEvent.where));
  217.         end
  218.         else if (not PtInRgn(theEvent.where, WindowPeek(theDialog)^.strucRgn)) then begin
  219.             beeper := LMGetDABeeper;
  220.             if (beeper <> nil) then begin
  221.                 CallBeeper(1, beeper);
  222.             end;
  223.         end
  224.         else if (partCode = inDrag) & (theDialog = wind) then begin { now, we have to handle the only thing DialogSelect doesn't do for us: dragging }
  225.             dragRect := GetGrayRgn^^.rgnBBox;
  226.             DragWindow(wind, theEvent.where, dragRect);
  227.             theEvent.what := nullEvent;
  228.         end;
  229.     end;
  230.  
  231.     procedure MovableModalDialog (filterProc: ProcPtr; var itemHit: Integer);
  232.         var
  233.             savePort: GrafPtr;
  234.             theDialog, junk_dialog: DialogPtr;
  235.             theEvent: EventRecord;
  236.             gotEvent: Boolean;
  237.     begin
  238.         itemHit := 0;
  239.         theDialog := FrontWindow;
  240.         if (theDialog <> nil) then begin
  241.             SetPort(theDialog);
  242.             repeat
  243.                 gotEvent := WaitNextEvent(kMovableModalEventMask, theEvent, 0, nil);
  244.                 SetPort(theDialog);
  245.  
  246.                 if (filterProc <> nil) & CallFilter(theDialog, theEvent, itemHit, filterProc) then begin
  247.                     Leave;
  248.                 end;
  249.  
  250.                 if (theEvent.what = mouseDown) & HandleMouseDown(theDialog, theEvent, itemHit) then begin
  251.                     Leave;
  252.                 end;
  253.  
  254.                 if (theEvent.what = keyDown) & (BAND(theEvent.modifiers, cmdKey) <> 0) & DoMenuChoice(theDialog, theEvent, itemHit, MenuKey(CHR(BAND(theEvent.message, charCodeMask)))) then begin
  255.                     Leave;
  256.                 end;
  257.  
  258.                 if IsDialogEvent(theEvent) & DialogSelect(theEvent, junk_dialog, itemHit) then begin
  259.                     Leave;
  260.                 end;
  261.             until false;
  262.         end;
  263.  
  264.     end;
  265.  
  266. end.